angular.module('feibo.common', [
    'feibo.common.directive',
    'feibo.common.service',
    'feibo.common.filter',
    'feibo.common.semantic.directive'
]);
angular.module('feibo.common.service', [])
    .service('CommonService', ['HttpService', '$state', '$filter', 'kvMap', function (HttpService, $state, $filter, kvMap) {
        var localDebug = FB_GLOBAL_CONFIG.debug;
        var iTime;
        var tokenText = kvMap.tokenText;
        var material = kvMap.material;
        var defaultPageSize = kvMap.restriction.paginate.defaultPageSize;
        return {
            arrLike2arr: function(arrLikeObj){
                return Array.prototype.slice.call(arrLikeObj);
            },
            loadingDataTips: function(){
                return HttpService.loadingDataTips();
            },
            showTips: function(messge, tipType){
                  var config = {
                         0: {
                            cssClass: 'top-news-green',
                            enUS: 'ok',
                            key: 'ok'
                         },
                         1: {
                            cssClass: 'top-news-ye',
                            enUS: 'warn',
                            key: 'warn'
                         },
                         2: {
                            cssClass: 'top-news-red',
                            enUS: 'error',
                            key: 'error'
                         },
                         vkMap: {
                            ok: 0,
                            warn: 1,
                            error: 2
                         }
                  };
                  var cssClassName;
                  if(tipType){
                    if(typeof tipType === 'number'){
                        cssClassName = config[tipType].cssClass;
                    }else if(typeof tipType === 'string'){
                        tipType = config.vkMap[tipType];
                        cssClassName = config[tipType].cssClass;
                    }else{
                        console.error('unsupported tipType:', tipType);
                    }
                  }
                  $('.top-news-box_01,.top-news_01').css('top',0+'px');
                  $('#fb-div-tips').removeClass('top-news-green top-news-ye top-news-red').addClass(cssClassName);
                  $('#fb-form-tips').text(messge);
                  window.setTimeout(function() {
                         $('.top-news_01,.top-news-box_01').css('top', -$('.top-news_01').height());
                  }, 3000);
            },
            showTips2: function(messge, tipType){
                             var cssClassName;
                             var config = {
                                     1: {
                                        cssClass: 'ok',
                                        key: 'ok'
                                     },
                                     2: {
                                        cssClass: 'warn',
                                        key: 'warn'
                                     },
                                     3: {
                                        cssClass: 'error',
                                        key: 'error'
                                     },
                                     vkMap: {
                                        ok: 1,
                                        warn: 2,
                                        error: 3
                                     }
                              };
                              if(tipType){
                                if(typeof tipType === 'number'){
                                    cssClassName = config[tipType].cssClass;
                                }else if(typeof tipType === 'string'){
                                    tipType = config.vkMap[tipType];
                                    cssClassName = config[tipType].cssClass;
                                }else{
                                    console.error('unsupported tipType:', tipType);
                                }
                          }
                          $('#msgTip').removeClass().addClass(cssClassName).text(messge);
                          $('#tips').fadeIn();
                          window.setTimeout(function() {
                                 $('#tips').fadeOut();
                          }, 3000);
                   },

            /*
             * 计算两个时间段 相隔 天数或月数
             * eg:   2016-12-29 --> 2017-01-02
             * 按天 --> getDay   --> 4
             * 按月 --> getMonth --> 1
             */
            getDays: function(start, end, type) {
                var nowStart = new Date(start);
                var nowEnd = new Date(end);
                var days;

                if (type == 'getMonth') {
                    start = start.split('-');
                    start = parseInt(start[0]) * 12 + parseInt(start[1]);
                    end = end.split('-');
                    end = parseInt(end[0]) * 12 + parseInt(end[1]);
                    days = Math.abs(end - start);
                } else if (type == 'getDay') {
                    days = (nowEnd - nowStart) / (24 * 60 * 60 * 1000);
                }
                return days;
            },
            // 格式化日期：yyyy-MM || yyyy-MM-dd
            formatDate: function(date, type) {
                var myyear = date.getFullYear();
                var mymonth = date.getMonth() + 1;
                var myweekday = date.getDate();
                var formatValue;

                if(mymonth < 10){
                    mymonth = '0' + mymonth;
                }
                if(myweekday < 10){
                    myweekday = '0' + myweekday;
                }

                if (type == 'getMonth') {
                    formatValue = myyear + '-' + mymonth;
                } else if (type == 'getDay') {
                    formatValue = myyear + '-' + mymonth + '-' + myweekday;
                }
                return formatValue;
            },
            /*
             * 日期格式化： 跨年显示年份，跨月显示月份
             * eg:   2016-11-29 --> 2017-02-02
             * 按天 --> getDay   --> ['2016-11-29', '30', '12-01',...,'31', '2017-01-01', '02', ..., '31', '02-01']
             * 按月 --> getMonth --> ['2016-11', '12', '2017-01', '02']
             */
            todoxAxisFormat: function(date, setDataType){
                var i;
                var val;
                var result = [];
                result[0] = date[0];

                for (i = 1; i <= date.length - 1; i++) {
                    if (date[i - 1].split('-')[0] == date[i].split('-')[0]) {
                        if (date[i - 1].split('-')[1] == date[i].split('-')[1]) {
                            if (setDataType == 'getMonth') {
                                val = '';
                            } else if (setDataType == 'getDay') {
                                val = date[i].split('-')[2];
                            }
                        } else {
                            if (setDataType == 'getMonth') {
                                val = date[i].split('-')[1];
                            } else if (setDataType == 'getDay') {
                                val = date[i].split('-')[1] + '-' + date[i].split('-')[2];
                            }
                        }
                    } else {
                        val = date[i];
                    }
                    result.push(val);
                }
                return result;
            },
            timeSlots: function(startTime, count, endTime){
                /* 本方法只获得H:mm，与年份无关，故放了假值，如果有更好办法会更换
                 * startTime: 开始时间点  eg: 7:00
                 * count: 总共时间点总个数 eg: 32
                 * endTime: 结束时间点    eg: 22:30
                 */
                if (!startTime || !count){
                    return false;
                }
                var i,
                    value,
                    myTime = new Date('2016/1/1 ' + startTime),
                    data = [];
                for(i = 0; i < count; i++) {
                    if (i == 0) {
                        value = $filter('fbdateformat')(new Date(myTime.setMinutes(myTime.getMinutes())), 'H:mm');
                    } else {
                        value = $filter('fbdateformat')(new Date(myTime.setMinutes(myTime.getMinutes() + 30)), 'H:mm');
                    }
                    data[i] = {};
                    data[i].timeArr = value;
                    data[i].cssIdArr = value.replace(/:/g, '');
                }
                return data;
            },
            logHttpResponse: function(response, funcName) {
                if (localDebug) {
                    if (funcName) {
                        console.warn('==>', funcName, ':start:<==');
                    }
                    console.log('response.data ==>', response.data);
                    if (funcName) {
                        console.warn('==>', funcName, ':end:<==');
                    }
                    console.error('---->>>> ~ <<<< ----');
                }
            },
            promptErrorMsg: function(statusCode, funcName, isClientSide, errMsg){
                 var that = this;
                 var sideType = 'Server';
                 if(isClientSide){
                    sideType ='Client';
                 }
                 that.showTips(sideType + ' Error: ' + statusCode + ':' + errMsg + ', func: ' + funcName, 'error');
            },
            handleHttpError: function(response, funcName) {
                var that = this;
                that.handleHttpCode(response);
                if (localDebug) {
                    if (funcName) {
                        console.warn('==>', funcName, ':start:<==');
                    }
                    console.error('response.status ==>', response.status);
                    console.error('response.data ==>', response.data);
                    if (funcName) {
                        console.warn('==>', funcName, ':end:<==');
                    }
                    console.error('---->>>> ~ <<<< ----');
                }
            },
            handleHttpCode: function(response) {
                var that = this;
                var statusCode = response.status;
                if (statusCode === 403) {
                    var errorMessage = '未登录,请重新登录';
                    that.showTips(errorMessage, 'error');
                    // window.location.href='/logout';
                    throw new Error(statusCode + ': ' + errorMessage, 'feibo.common.service.js');
                } else if (statusCode === 500) {
                    // that.showTips('服务器500错误,请联系管理员', 'error');
                } else if (statusCode === -1){
                    that.showTips('请求超时', 'error');
                }else{
                    that.showTips('服务器错误: ' + statusCode, 'error');
                }
            },
            cloneMapping: function (srcObj, excludedProps) {
                var ret = {};
                for (var p in srcObj) {
                    if (srcObj.hasOwnProperty(p)) {
                        if (excludedProps.indexOf(p) === -1) {
                            ret[p] = srcObj[p];
                        }
                    }
                }
                return ret;
            },
            concatenateZero: function(targetNumber, isZeroBased){
                                if(isZeroBased){
                                   targetNumber += 1;
                                }
                                if(targetNumber < 10){
                                   return '0' + targetNumber;
                                }else{
                                   return targetNumber;
                                }
            },
            previewMaterial: function(materialId){
                if (materialId) {
                    layer.open({
                         type: 2,
                         title: false,
                         area: ['827px', '650px'],
                         shade: 0.8,
                         closeBtn: true,
                         shadeClose: true,
                         content: material + 'material/preview?mid=' + materialId
                     });
                } else {
                    if (localDebug) {
                        console.error('==> previewMaterial: no materialId<==');
                    }
                }
            },
            previewImage: function(image){
                if (image) {
                    layer.open({
                         type: 2,
                         title: false,
                         area: ['827px', '650px'],
                         shade: 0.8,
                         closeBtn: true,
                         shadeClose: true,
                         content: $filter('absoluteUrl')(image)
                     });
                } else {
                    if (localDebug) {
                        console.error('==> previewImage: no image<==');
                    }
                }
            },
            unitConvert: { // 单位换算
                fen2yuan: function (fen) {
                    return (+fen).toFixed() / 100.0;
                }
            },
            padZero: function (number) {
                if ((+number) < 10) {
                    return '0' + number;
                }
                return number;
            },
            getCurrentDate: function () {
                var date = new Date();
                var year = date.getFullYear();
                var month = date.getMonth() + 1;
                month = this.padZero(month);
                var day = date.getDate();
                day = this.padZero(day);
                return year + '-' + month + '-' + day;
            },
            getCurrentDatetime: function(offset, notShowSeconds){
                // offset is minutes
                var date = new Date();
                if(offset){
                   date.setTime(date.getTime() + (offset * 60 * 1000));
                }
                var year = date.getFullYear();
                var month = date.getMonth() + 1;
                var day = date.getDate();
                var hours = date.getHours();
                var minutes = date.getMinutes();
                var seconds = date.getSeconds();

                month = this.padZero(month);
                day = this.padZero(day);
                hours = this.padZero(hours);
                minutes = this.padZero(minutes);
                seconds = this.padZero(seconds);

                var base = year + '-' + month + '-' + day + ' ' + hours + ':' + minutes;
                if(notShowSeconds){
                    return base;
                }
                return base + ':' + seconds;
            },
            isInDateRange: function (date, before, after) {
                          // before, after 单位是分钟
                          var ret = false;
                          var left, right;
                          var baseMs = new Date(date).getTime();
                          var currentDateMs = new Date().getTime();
                          if (before) {
                              before = +before;
                              left = baseMs - (before * 60 * 1000);
                          } else {
                              left = Number.NEGATIVE_INFINITY;
                          }

                          if (after) {
                              right = +right;
                              right = baseMs + (after * 60 * 1000);
                          } else {
                              right = Number.POSITIVE_INFINITY;
                          }
                          if (currentDateMs >= left && currentDateMs <= right) {
                              ret = true;
                          }
                          return ret;
            },
            isTheSameDay: function (base, compare) {
                var baseDate, compareDate;
                if (base instanceof Date) {
                    baseDate = base;
                } else {
                    baseDate = new Date(base);
                }
                if (compare instanceof Date) {
                    compareDate = compare;
                } else {
                    compareDate = new Date(compare);
                }

                var baseX = new Date();
                baseX.setTime(baseDate.getTime());
                baseX.setHours(0, 0, 0, 0);
                var compareY = new Date();
                compareY.setTime(compareDate.getTime());
                compareY.setHours(0, 0, 0, 0);

                var ret = baseX.getTime() === compareY.getTime();
                return ret;
            },
            needDisableTime: function (datetime, minAfterHour) { // 是否需要 disable 某些上课时间
                var delta = (new Date(datetime).getTime() - Date.now());
                var gap = minAfterHour * 60 * 60 * 1000;
                if(delta > gap){
                   return false;
                }

                return true;
            },
            /**
             * 获取验证吗
             */
            getCaptcha: function () {
                return HttpService.get(ENDPOINTS.other.captcha, null, false, false);
            },
            paginate: function (cssId, loadingPageIndex, totalPageNum, callback) {
                laypage({
                    cont: cssId,
                    pages: totalPageNum,
                    skin: '#00a0e9',
                    groups: 3,
                    prev: '<',
                    next: '>',
                    skip: true,
                    curr: loadingPageIndex,
                    jump: function (obj, first) {
                        if (!first) {
                            callback(obj.curr);
                        }
                    }
                });
            },
            dateHelper: function () { // 日期帮助类
                return {
                    getTodayRange: function (datePattern) {
                        var pattern = datePattern || 'yyyy-MM-dd HH:mm:ss';
                        var ret = {};
                        var today = new Date();
                        today.setHours(0, 0, 0, 0);
                        var tomorrow = new Date();
                        tomorrow.setHours(0, 0, 0, 0);
                        tomorrow.setDate(tomorrow.getDate() + 1);
                        ret.start = $filter('date')(today, pattern);
                        ret.end = $filter('date')(tomorrow, pattern);
                        return ret;
                    },
                    getDayRelative: function (date) { // 获取指定日期相对于当前日期的偏移量
                        var shadowDate = new Date();
                        shadowDate.setTime(date.getTime());
                        var dateFormat = function (date) {
                            var concatenateZero = function (targetNumber, isZeroBased) {
                                if (isZeroBased) {
                                    targetNumber += 1;
                                }
                                if (targetNumber < 10) {
                                    return '0' + targetNumber;
                                } else {
                                    return targetNumber;
                                }
                            };
                            var year = date.getFullYear();
                            var month = date.getMonth();
                            month = concatenateZero(month, true);
                            var day = date.getDate();
                            day = concatenateZero(day);
                            return year + '/' + month + '/' + day;
                        };

                        var today = new Date();
                        today.setHours(0, 0, 0, 0);
                        var yesterday = new Date();
                        yesterday.setHours(0, 0, 0, 0);
                        yesterday.setDate(yesterday.getDate() - 1);
                        var tomorrow = new Date();
                        tomorrow.setHours(0, 0, 0, 0);
                        tomorrow.setDate(tomorrow.getDate() + 1);
                        shadowDate.setHours(0, 0, 0, 0);
                        var compareDateInMs = shadowDate.getTime();
                        var key;
                        var otherDate;

                        if (compareDateInMs === today.getTime()) {
                            key = '0';
                        } else if (compareDateInMs === yesterday.getTime()) {
                            key = '-1';
                        } else if (compareDateInMs === tomorrow.getTime()) {
                            key = '1';
                        } else {
                            key = 'other';
                            otherDate = dateFormat(shadowDate);
                        }

                        return {
                            '-1': {
                                enUS: 'Yesterday',
                                zhCN: '昨天'
                            },
                            '0': {
                                enUS: 'Today',
                                zhCN: '今天'
                            },
                            '1': {
                                enUS: 'Tomorrow',
                                zhCN: '明天'
                            },
                            'other': {
                                enUS: otherDate,
                                zhCN: otherDate
                            }
                        }[key];
                    },
                    getTimeAPM: function (date) {
                        var kvM = {
                            'AM': {
                                enUS: 'A.M',
                                zhCN: '上午'
                            },
                            'PM': {
                                enUS: 'P.M',
                                zhCN: '下午'
                            }
                        };
                        var addZeroPrefix = function (intVal) {
                            if (intVal <= 9) {
                                intVal = '0' + intVal;
                            }
                            return intVal;
                        };
                        var hours = date.getHours();
                        var key;
                        if (hours >= 0 && hours <= 12) {
                            key = 'AM';
                        } else {
                            key = 'PM';
                        }

                        var minutes = addZeroPrefix(date.getMinutes());
                        hours = addZeroPrefix(hours);
                        var time = hours + ':' + minutes;

                        kvM[key].time = time;
                        return kvM[key];
                    }
                };
            },
            upload2Qiniu: function (containerCssId, monitorDivCssId, eventConfig, filters, auto_start) {
                return Qiniu.uploader({
                    runtimes: 'html5,flash,html4',
                    container: containerCssId,
                    browse_button: monitorDivCssId,
                    dragdrop: true,
                    drop_element: monitorDivCssId,
                    chunk_size: '4mb',
                    auto_start: !auto_start,
                    max_file_size: '30mb',
                    max_retries: 3,
                    uptoken_url: ENDPOINTS.qiniu.upload,
                    domain: ENDPOINTS.qiniu.domain,
                    bucket_domain: ENDPOINTS.qiniu.bucketDomain,
                    get_new_uptoken: false,
                    flash_swf_url: '../../v2/lib/plupload-2.1.8/js/Moxie.swf',
                    filters: filters || {},
                    init: eventConfig()
                });
            },
            commonQiniuUploadEventConfig: function () {
                return {
                    'FilesAdded': function (up, files) {
                        plupload.each(files, function (file) {
                            // 文件添加进队列后,处理相关的事情
                        });
                    },
                    'BeforeUpload': function (up, file) {
                        // 每个文件上传前,处理相关的事情
                    },
                    'UploadProgress': function (up, file) {
                        // 每个文件上传时,处理相关的事情
                    },
                    'FileUploaded': function (up, file, info) {
                        // 每个文件上传成功后,处理相关的事情
                        // 其中 info 是文件上传成功后，服务端返回的json，形式如
                        // {
                        //    "hash": "Fh8xVqod2MQ1mocfI4S4KpRL6D98",
                        //    "key": "gogopher.jpg"
                        //  }
                        // 参考http://developer.qiniu.com/docs/v6/api/overview/up/response/simple-response.html

                        // var domain = up.getOption('domain');
                        // var res = parseJSON(info);
                        // var sourceLink = domain + res.key; 获取上传成功后的文件的Url
                        console.error('upload successed');
                    },
                    'Error': function (up, err, errTip) {
                        //上传出错时,处理相关的事情
                    },
                    'UploadComplete': function () {
                        //队列文件处理完毕后,处理相关的事情
                    },
                    'Key': function (up, file) {
                        // 若想在前端对每个文件的key进行个性化处理，可以配置该函数
                        // 该配置必须要在 unique_names: false , save_key: false 时才生效

                        var key = CryptoJS.MD5(file.name);
                        // do something with key here
                        return key;
                    }
                };
            },
            semanticInstantSearch: function (queryConfig) {
                var url = queryConfig.url;
                var cssId = queryConfig.cssId;
                var container = queryConfig.container;
                var propName = queryConfig.propName;
                var propChain = queryConfig.propChain || ['data'];
                var resultsPropsConfig = queryConfig.resultsPropsConfig;
                var separator = ' | ' || resultsPropsConfig.separator;
                // resultsPropsConfig example:
                // {
                //    title: ['id', 'nickname'],
                //    value: ['id'],
                //    separator: '|'
                // }
                var onSelectCallback = queryConfig.callback;
                var callbackArgs = queryConfig.callbackArgs;
                var onResponse = queryConfig.onResponse;
                var ret;
                if (!onResponse) {
                    onResponse = function (response) {
                        ret = response;
                        var arr = [];
                        var result = {
                            results: arr
                        };
                        if (FB_GLOBAL_CONFIG.debug) {
                            console.warn('semanticInstantSearch response: ', ret);
                        }
                        for (var i = 0, length = propChain.length; i < length; i++) {
                            ret = ret[propChain[i]];
                        }
                        ret.forEach(
                            function (element) {
                                arr.push({
                                    title: resultsPropsConfig.title.map(
                                        function (ele) {
                                            // 添加title值可取对象属性值(obj.XX),只支持二级对象属性值
                                            var el = ele.split('.');
                                            var len = el.length;
                                            if (len > 1){
                                                return element[el[0]][el[1]]
                                            }
                                            return element[el[0]];
                                        }
                                    ).join(separator),
                                    value: resultsPropsConfig.value.map(
                                        function (ele) {
                                            return element[ele];
                                        }
                                    ).join(separator),
                                    data: element
                                });
                            }
                        );

                        if (FB_GLOBAL_CONFIG.debug) {
                            console.warn('semanticInstantSearch Results: ', result);
                        }
                        return result;
                    };
                }
                var searchConfig = {
                    apiSettings: {
                        url: url,
                        beforeXHR: function (xhr) {
                            xhr.setRequestHeader('Authorization', tokenText);
                        },
                        onResponse: onResponse
                    },
                    onSelect: function (result) {
                        container[propName] = result.value;
                        container.originalData = result.data;
                        if (onSelectCallback) {
                            if (callbackArgs) {
                                onSelectCallback(callbackArgs);
                            } else {
                                onSelectCallback();
                            }
                        }
                    }
                };

                $('#' + cssId).search(searchConfig);
            },
            semanticInstantSearchDropdown: function (queryConfig) {
                var url = queryConfig.url;
                var cssId = queryConfig.cssId;
                var container = queryConfig.container;
                var propName = queryConfig.propName;
                var propChain = queryConfig.propChain || ['data'];
                var token = queryConfig.token || tokenText;
                var resultsPropsConfig = queryConfig.resultsPropsConfig;
                var separator = ' | ' || resultsPropsConfig.separator;
                var onSelectCallback = queryConfig.callback;
                var callbackArgs = queryConfig.callbackArgs;
                var onResponse = queryConfig.onResponse;
                var ret;
                if (!onResponse) {
                    onResponse = function (response) {
                        ret = response;
                        var arr = [];
                        var result = {
                            results: arr
                        };
                        if (FB_GLOBAL_CONFIG.debug) {
                            console.warn('semanticInstantSearch response: ', ret);
                        }
                        for (var i = 0, length = propChain.length; i < length; i++) {
                            ret = ret[propChain[i]];
                        }
                        ret.forEach(
                            function (element) {
                                arr.push({
                                    name: resultsPropsConfig.name.map(
                                        function (ele) {
                                            return element[ele];
                                        }
                                    ).join(separator),
                                    value: resultsPropsConfig.value.map(
                                        function (ele) {
                                            return element[ele];
                                        }
                                    ).join(separator),
                                    data: element
                                });
                            }
                        );

                        if (FB_GLOBAL_CONFIG.debug) {
                            console.warn('semanticInstantSearch Results: ', result);
                        }
                        return result;
                    };
                }
                var searchConfig = {
                    apiSettings: {
                        url: url,
                        beforeXHR: function (xhr) {
                            xhr.setRequestHeader('Authorization', token);
                        },
                        onResponse: onResponse
                    },
                    onAdd: function (addedValue, addedText, $addedChoice) {
                        if (container[propName].indexOf(addedValue) == -1) {
                            container[propName].push(addedValue);
                        }
                        if (onSelectCallback) {
                            if (callbackArgs) {
                                onSelectCallback(callbackArgs);
                            } else {
                                onSelectCallback();
                            }
                        }
                    },
                    onRemove: function(removedValue, removedText, $removedChoice){
                        for(var i = 0; i < container[propName].length; i++) {
                            if(container[propName][i] == removedValue) {
                              container[propName].splice(i, 1);
                              break;
                            }
                        }
                        if (onSelectCallback) {
                            if (callbackArgs) {
                                onSelectCallback(callbackArgs);
                            } else {
                                onSelectCallback();
                            }
                        }
                    }
                };

                $('#' + cssId).dropdown(searchConfig);
            },
            extractProperties: function (targetArr, propName, separator) {
                var tempArr = [];
                targetArr.forEach(
                    function (element) {
                        tempArr.push(element[propName]);
                    }
                );
                return tempArr.join(separator);
            },
            fetch: function (queryConfig) {
                var that = this;
                var httpGetParams = queryConfig.httpGetParams || {};
                var container = queryConfig.container;
                var propName = queryConfig.propName;
                var funcName = queryConfig.funcName;
                var callback = queryConfig.callback;
                var endpoint = queryConfig.endpoint;

                if(localDebug){
                    console.warn(funcName, ' httpGetParams:', httpGetParams);
                }

                return HttpService.get(endpoint, httpGetParams).then(
                    function (response) {
                        var ret = response.data;
                        var statusCode = ret.code;
                        that.logHttpResponse(response, funcName);
                        if (statusCode === 1000) {
                            container[propName] = ret.data.entries;
                            if (callback) {
                                callback();
                            }
                            return ret;
                        } else {
                            that.promptErrorMsg(statusCode, funcName, true);
                            throw new Error(feiboCommonFuncs.statusCodeMapping(statusCode), 'feibo.common.service.js');
                        }
                    },
                    function (response) {
                        that.promptErrorMsg(response.data.code, funcName);
                        that.handleHttpError(response, funcName);
                        throw new Error(feiboCommonFuncs.statusCodeMapping(statusCode), 'feibo.common.service.js');
                    }
                );
            },
            polyfillEndpoint: function(endpoint, urlPlaceholder){
                var pattern = /:((?!\d+)\w+)/g;
                var kvArr = [];
                var compose = function(matchedData){
                    var key, placeholder;
                    if(matchedData !== null){
                        kvArr.push({placeholder: matchedData[0], key: matchedData[1]});
                    }
                };

                var matchedData = pattern.exec(endpoint);
                    compose(matchedData);
                    while(matchedData !== null){
                         matchedData = pattern.exec(endpoint);
                         compose(matchedData);
                    }
                kvArr.forEach(function(element){
                      var key = element.key;
                      var placeholder = element.placeholder;
                      endpoint = endpoint.replace(placeholder, urlPlaceholder[key]);
                });
                return endpoint;
            },
            timeoutShow: function(res){
                var ret = false;
                if(res.status === -1){
                    this.showTips2('请求超时', 'warn');
                    ret = true;
                }
                return ret;
            },
            /**
             * queryConfig
             * 属性
             * @httpGetParams get 请求参数
             * @container $scope容器
             * @propName  接受数据的属性
             * @funcName  执行的函数（log 使用）
             * @propChain 获取返回数据的属性
             * @endpoint  url
             * @urlPlaceholder  url 参数 example endpoint+/a/{b}/{c}这样的url
             */
            get: function (queryConfig) {
                var that = this;
                var httpGetParams = queryConfig.httpGetParams || {};
                var pageSize = httpGetParams.page_size;
                    if(typeof pageSize === 'number' && pageSize < 1){ // 删除 page_size 属性, 因为 express 不支持 query params
                        delete httpGetParams.page_size;
                    }else{
                        httpGetParams.page_size = httpGetParams.page_size || defaultPageSize;
                    }
                var container = queryConfig.container;
                var propName = queryConfig.propName;
                var funcName = queryConfig.funcName;
                var endpoint = queryConfig.endpoint;
                var propChain = queryConfig.propChain;
                var urlPlaceholder = queryConfig.urlPlaceholder;
                var promptUserCodeArr = queryConfig.promptUserCode; // 直接提示用户的状态码
                var showLoadLayer;
                    if(queryConfig.showLoadLayer === undefined){
                       showLoadLayer = true;
                    }else{
                       showLoadLayer = queryConfig.showLoadLayer;
                    }
                    if(promptUserCodeArr && Array.isArray(promptUserCodeArr)){
                       promptUserCodeArr = promptUserCodeArr.concat(4002);
                    }else{
                       promptUserCodeArr = [4002];
                    }
                var gotoNextStepCodeArr = queryConfig.gotoNextStepCode; // 直接跳转到下一步的状态码
                var routeToNext = queryConfig.routeToNext; // 路由到另外一个页面
                if (urlPlaceholder) {
                   if(Array.isArray(urlPlaceholder)){
                     endpoint = endpoint + '/' + urlPlaceholder.join('/');
                   }else{
                     endpoint = that.polyfillEndpoint(endpoint, urlPlaceholder);
                   }
                }

                if (!propChain) {
                    alert('propChain 必须配置');
                    return;
                }

                if(localDebug){
                    console.warn(funcName, ' httpGetParams:', httpGetParams);
                }

                return HttpService.get(endpoint, httpGetParams, !showLoadLayer).then(
                    function (response) {
                        var ret = response.data;
                        var statusCode = ret.code;
                        var errorMessage = feiboCommonFuncs.statusCodeMapping(statusCode);
                        that.logHttpResponse(response, funcName);
                        if (ret.success || statusCode === 1000) {
                            if (container && propName && propChain) {
                                for (var i = 0; i < propChain.length; i++) {
                                    ret = ret[propChain[i]];
                                }
                                container[propName] = ret;
                            }
                            return response.data;
                        } else {
                            var promptBool = promptUserCodeArr && promptUserCodeArr.includes(statusCode);
                            var gotoNextBool = gotoNextStepCodeArr && gotoNextStepCodeArr.includes(statusCode) && routeToNext;
                            var gotoLogError = !(promptBool || gotoNextBool);
                            if (promptBool) {
                                that.showTips(statusCode + ': ' + feiboCommonFuncs.statusCodeMapping(statusCode), 'warn');
                                return response.data;
                            }
                            if (gotoNextBool) {
                                routeToNext();
                            }

                            if (gotoLogError) {
                                that.promptErrorMsg(statusCode, funcName, true, errorMessage);
                                throw new Error(statusCode + ': ' + errorMessage, 'feibo.common.service.js');
                            }
                            return response.data;
                        }
                    },
                    function (response) {
                        if(that.timeoutShow(response)){
                            return {success: false};
                        }

                        var statusCode = response.data.code;
                        var errorMessage = feiboCommonFuncs.statusCodeMapping(statusCode);
                        that.handleHttpError(response, funcName);
                        console.error('response.status ==>', response.status);
                        if (response.status === 500) {
                            $state.go('error500');
                        } else {
                            that.promptErrorMsg(statusCode, funcName, false, errorMessage);
                        }
                        throw new Error(statusCode + ': ' + errorMessage, 'feibo.common.service.js');
                    }
                );
            },
            patch: function (patchConfig) {
                var that = this;
                var funcName = patchConfig.funcName;
                var container = patchConfig.container;
                var propName = patchConfig.propName;
                var propChain = patchConfig.propChain;
                var urlPlaceholder = patchConfig.urlPlaceholder;
                var httpPatchData = patchConfig.httpPatchData || {};
                var successMsg = patchConfig.successMsg;
                var errorMsg = patchConfig.errorMsg;
                var endpoint = patchConfig.endpoint;
                var promptUserCodeArr = patchConfig.promptUserCode; // 直接提示用户的状态码
                    if(promptUserCodeArr && Array.isArray(promptUserCodeArr)){
                       promptUserCodeArr = promptUserCodeArr.concat(4002);
                    }else{
                       promptUserCodeArr = [4002];
                    }
                var gotoNextStepCodeArr = patchConfig.gotoNextStepCode; // 直接跳转到下一步的状态码
                var routeToNext = patchConfig.routeToNext; // 路由到另外一个页面

                if (!successMsg || !errorMsg) {
                    alert('you must config the successMsg and errorMsg propertis');
                    return;
                }

                if (urlPlaceholder) {
                   if(Array.isArray(urlPlaceholder)){
                     endpoint = endpoint + '/' + urlPlaceholder.join('/');
                   }else{
                     endpoint = that.polyfillEndpoint(endpoint, urlPlaceholder);
                   }
                }

                if(localDebug){
                    console.warn(funcName, ' httpPatchData: ', httpPatchData);
                }

                return HttpService.patch(endpoint, httpPatchData).then(
                    function (response) {
                        var ret = response.data;
                        var statusCode = ret.code;
                        var errorMessage = feiboCommonFuncs.statusCodeMapping(statusCode);
                        that.logHttpResponse(response, funcName);
                        if (statusCode === 1000 || statusCode === 1001) {
                            if (statusCode === 1000) {
                                if (container && propName && propChain) {
                                    for (var i = 0; i < propChain.length; i++) {
                                        ret = ret[propChain[i]];
                                    }
                                    container[propName] = ret;
                                }
                            }
                            that.showTips(successMsg, 'ok');
                            return response.data;
                        } else {
                            var promptBool = promptUserCodeArr && promptUserCodeArr.includes(statusCode);
                            var gotoNextBool = gotoNextStepCodeArr && gotoNextStepCodeArr.includes(statusCode) && routeToNext;
                            var gotoLogError = !(promptBool || gotoNextBool);
                            if (promptBool) {
                                that.showTips(statusCode + ': ' + feiboCommonFuncs.statusCodeMapping(statusCode), 'warn');
                            }
                            if (gotoNextBool) {
                                routeToNext();
                            }
                            if (gotoLogError) {
                                that.promptErrorMsg(statusCode, funcName, true, errorMessage);
                                throw new Error(statusCode + ': ' + errorMessage, 'feibo.common.service.js');
                            }
                            return response.data;
                        }
                    },
                    function (response) {
                        if(that.timeoutShow(response)){
                            return {success: false};
                        }

                        var statusCode = response.data.code;
                        var errorMessage = feiboCommonFuncs.statusCodeMapping(statusCode);
                        that.handleHttpError(response, funcName);
                        if (response.status === 500) {
                            $state.go('error500');
                        } else {
                            that.promptErrorMsg(statusCode, funcName, false, errorMessage);
                        }
                        throw new Error(statusCode + ': ' + errorMessage, 'feibo.common.service.js');
                    }
                );

            },
            post: function (postConfig) {
                var that = this;
                var httpPostData = postConfig.httpPostData || {};
                var container = postConfig.container;
                var propName = postConfig.propName;
                var funcName = postConfig.funcName;
                var successMsg = postConfig.successMsg;
                var errorMsg = postConfig.errorMsg;
                var callback = postConfig.callback;
                var propChain = postConfig.propChain || ['data'];
                var urlPlaceholder = postConfig.urlPlaceholder;
                var endpoint = postConfig.endpoint;
                var promptUserCodeArr = postConfig.promptUserCode; // 直接提示用户的状态码
                    if(promptUserCodeArr && Array.isArray(promptUserCodeArr)){
                       promptUserCodeArr = promptUserCodeArr.concat(4002);
                    }else{
                       promptUserCodeArr = [4002];
                    }
                var gotoNextStepCodeArr = postConfig.gotoNextStepCode; // 直接跳转到下一步的状态码
                var routeToNext = postConfig.routeToNext; // 路由到另外一个页面
                /*
                 * code 分类
                 * 1: OK code, e.g: 1000, 1001
                 * 2: Error code, e.g: 2000, 2001
                 * 3: Prompt user code: e.g: 4001
                 * 4: Goto next step code: e.g: 4026
                 * 我们主要处理第三类和第四类,第二类直接打印错误日志
                 */

                 if (urlPlaceholder) {
                    if(Array.isArray(urlPlaceholder)){
                      endpoint = endpoint + '/' + urlPlaceholder.join('/');
                    }else{
                      endpoint = that.polyfillEndpoint(endpoint, urlPlaceholder);
                    }
                 }

                if (!successMsg || !errorMsg) {
                    alert('you must config the successMsg and errorMsg properties');
                    return;
                }

                if(localDebug){
                    console.warn(funcName, ' httpPostData:', httpPostData);
                }

                return HttpService.post(endpoint, httpPostData).then(
                    function (response) {
                        that.logHttpResponse(response, funcName);
                        var ret = response.data;
                        var statusCode = ret.code;
                        var errorMessage = feiboCommonFuncs.statusCodeMapping(statusCode);
                        if (statusCode === 1000 || statusCode === 1001) {
                            if (statusCode === 1000) {
                                if (ret.data) {
                                    if (container && propName && propChain) {
                                        for (var i = 0; i < propChain.length; i++) {
                                            ret = ret[propChain[i]];
                                        }
                                        container[propName] = ret;
                                    }
                                }
                            }
                            that.showTips(successMsg, 'ok');
                            if (callback) {
                                callback();
                            }
                            return response.data;
                        } else {
                            var promptBool = promptUserCodeArr && promptUserCodeArr.includes(statusCode);
                            var gotoNextBool = gotoNextStepCodeArr && gotoNextStepCodeArr.includes(statusCode) && routeToNext;
                            var gotoLogError = !(promptBool || gotoNextBool);
                            if (promptBool) {
                                that.showTips(statusCode + ': ' + feiboCommonFuncs.statusCodeMapping(statusCode), 'warn');
                                return response.data;
                            }
                            if (gotoNextBool) {
                                routeToNext();
                            }

                            if (gotoLogError) {
                                that.promptErrorMsg(statusCode, funcName, true, errorMessage);
                                throw new Error(statusCode + ': ' + errorMessage, 'feibo.common.service.js');
                            }
                            return response.data;
                        }
                    },
                    function (response) {
                        if(that.timeoutShow(response)){
                            return {success: false};
                        }

                        var statusCode = response.data.code;
                        var errorMessage = feiboCommonFuncs.statusCodeMapping(statusCode);
                        that.handleHttpError(response, funcName);
                        if (response.status === 500) {
                            $state.go('error500');
                        } else {
                            that.promptErrorMsg(statusCode, funcName, false, errorMessage);
                        }
                        throw new Error(statusCode + ': ' + errorMessage, 'feibo.common.service.js');
                    }
                );
            },
            delete: function (deleteConfig) {
                var that = this;
                var httpdeleteData = deleteConfig.httpdeleteData || {};
                var funcName = deleteConfig.funcName;
                var successMsg = deleteConfig.successMsg;
                var errorMsg = deleteConfig.errorMsg;
                var endpoint = deleteConfig.endpoint;
                var callback = deleteConfig.callback;
                var urlPlaceholder = deleteConfig.urlPlaceholder;

                if (urlPlaceholder) {
                   if(Array.isArray(urlPlaceholder)){
                     endpoint = endpoint + '/' + urlPlaceholder.join('/');
                   }else{
                     endpoint = that.polyfillEndpoint(endpoint, urlPlaceholder);
                   }
                }

                if (!successMsg || !errorMsg) {
                    alert('you must config the successMsg and errorMsg propertis');
                    return;
                }

                if(localDebug){
                    console.warn(funcName, ' deleteEndpoint:', endpoint);
                }

                return HttpService.delete(endpoint,httpdeleteData).then(
                    function (response) {
                        var statusCode = response.data.code;
                        if (statusCode === 1000 || statusCode === 1001) {
                            that.showTips(successMsg, 'ok');
                            if (callback) {
                                callback();
                            }
                        } else {
                            that.showTips(statusCode + ':' + feiboCommonFuncs.statusCodeMapping(statusCode), 'warn');
                        }
                        return response.data;
                    },
                    function (response) {
                        if(that.timeoutShow(response)){
                            return {success: false};
                        }

                        var statusCode = response.data.code;
                        var errorMessage = feiboCommonFuncs.statusCodeMapping(statusCode);
                        that.handleHttpError(response, funcName);
                        if (response.status === 500) {
                            $state.go('error500');
                        } else {
                            that.promptErrorMsg(statusCode, funcName, false, errorMessage);
                        }
                        throw new Error(statusCode + ': ' + errorMessage, 'feibo.common.service.js');
                    }
                );

            },
            put: function (putConfig) {
                var that = this;
                var httpPutData = putConfig.httpPutData || {};
                var container = putConfig.container;
                var propName = putConfig.propName;
                var funcName = putConfig.funcName;
                var successMsg = putConfig.successMsg;
                var errorMsg = putConfig.errorMsg;
                var callback = putConfig.callback;
                var propChain = putConfig.propChain || ['data'];
                var urlPlaceholder = putConfig.urlPlaceholder;
                var endpoint = putConfig.endpoint;
                var promptUserCodeArr = putConfig.promptUserCode; // 直接提示用户的状态码
                    if(promptUserCodeArr && Array.isArray(promptUserCodeArr)){
                       promptUserCodeArr = promptUserCodeArr.concat(4002);
                    }else{
                       promptUserCodeArr = [4002];
                    }
                var gotoNextStepCodeArr = putConfig.gotoNextStepCode; // 直接跳转到下一步的状态码
                var routeToNext = putConfig.routeToNext; // 路由到另外一个页面

                if (urlPlaceholder) {
                   if(Array.isArray(urlPlaceholder)){
                     endpoint = endpoint + '/' + urlPlaceholder.join('/');
                   }else{
                     endpoint = that.polyfillEndpoint(endpoint, urlPlaceholder);
                   }
                }

                if (!successMsg || !errorMsg) {
                    alert('you must config the successMsg and errorMsg properties');
                    return;
                }

                if(localDebug){
                    console.warn(funcName, ' httpPutData:', httpPutData, urlPlaceholder);
                }

                return HttpService.put(endpoint, httpPutData).then(
                    function (response) {
                        that.logHttpResponse(response, funcName);
                        var ret = response.data;
                        var statusCode = ret.code;
                        var errorMessage = feiboCommonFuncs.statusCodeMapping(statusCode);
                        if (statusCode === 1000 || statusCode === 1001) {
                            if (statusCode === 1000) {
                                if (ret.data) {
                                    if (container && propName && propChain) {
                                        for (var i = 0; i < propChain.length; i++) {
                                            ret = ret[propChain[i]];
                                        }
                                        container[propName] = ret;
                                    }
                                }
                            }
                            that.showTips(successMsg, 'ok');
                            if (callback) {
                                callback();
                            }
                            return response.data;
                        } else {
                            var promptBool = promptUserCodeArr && promptUserCodeArr.includes(statusCode);
                            var gotoNextBool = gotoNextStepCodeArr && gotoNextStepCodeArr.includes(statusCode) && routeToNext;
                            var gotoLogError = !(promptBool || gotoNextBool);
                            if (promptBool) {
                                that.showTips(statusCode + ': ' + feiboCommonFuncs.statusCodeMapping(statusCode), 'warn');
                            }
                            if (gotoNextBool) {
                                routeToNext();
                            }

                            if (gotoLogError) {
                                that.promptErrorMsg(statusCode, funcName, true, errorMessage);
                                throw new Error(statusCode + ': ' + errorMessage, 'feibo.common.service.js');
                            }
                            return response.data;
                        }
                    },
                    function (response) {
                        if(that.timeoutShow(response)){
                            return {success: false};
                        }

                        var statusCode = response.data.code;
                        var errorMessage = feiboCommonFuncs.statusCodeMapping(statusCode);
                        that.handleHttpError(response, funcName);
                        if (response.status === 500) {
                            $state.go('error500');
                        } else {
                            that.promptErrorMsg(statusCode, funcName, false, errorMessage);
                        }
                        throw new Error(statusCode + ': ' + errorMessage, 'feibo.common.service.js');
                    }
                );
            },
            generateIdxArr: function (pageNumber) {
                var ret = [];
                var i;
                for (i = 1; i <= pageNumber; i++) {
                    ret.push(i);
                }
                return ret;
            },
            hideModal: function (cssId, cssClazz) {
                var selector;
                if (cssId) {
                    selector = '#' + cssId;
                    $(selector).modal('hide');
                }

                if (cssClazz) {
                    selector = '.' + cssClazz;
                    $(selector).modal('hide');
                }

                console.error('executed');
            },
            showModal: function (cssId, cssClazz) {
                var selector;
                if (cssId) {
                    selector = '#' + cssId;
                    $(selector).modal('show');
                }

                if (cssClazz) {
                    selector = '.' + cssClazz;
                    $(selector).modal('show');
                }
            },
            getSelectedOptions: function (elementId) {
                var select = document.getElementById(elementId);
                var result = [];
                var options = select && select.options;
                var opt;
                var idx, lgth;
                for (idx = 0, lgth = options.length; idx < lgth; idx++) {
                    opt = options[idx];
                    if (opt.selected) {
                        result.push(opt.value || opt.text);
                    }
                }
                return result;
            },
            showMoreulli: function (elemetclas) {
                var addhover = function () {
                    var ele = document.getElementsByClassName(elemetclas);
                    $(ele).mouseover(function () {
                        $(this).children('ul').show();
                    });
                    $(ele).mouseout(function () {
                        $(this).children('ul').hide();
                    });
                };
                if (iTime) {
                    clearTimeout(iTime);
                }
                iTime = setTimeout(addhover, 400);
            },
            valiCellPhoeunique: function (cellphone, pk) {
                var url = ENDPOINTS.other.valid.uniqueCellphone + '/' + cellphone + '/unique';
                var postdata = { pk: pk };
                return HttpService.post(url, postdata);
            },
            valiEmailunique: function (email, pk) {
                var url = ENDPOINTS.other.valid.uniqueEmail + '/' + email + '/unique';
                var postdata = { pk: pk };
                return HttpService.post(url, postdata);
            },

        };
    }])
    .factory('HttpService', ['$http', '$q', '$timeout','kvMap', function ($http, $q, $timeout, kvMap) {
        var tokenText = kvMap.tokenText;
        var layerIndex, layercount = 0;
        var closeLoad = function () {
            layercount -= 1;
            $timeout(function () {
                if (layercount === 0) {
                    layer.close(layerIndex);
                    layerIndex = null;
                }
            }, 100);
        };
        return {
            getpersoninfo: function (url) {
                return this.get(url, null, true, true);
            },
            get: function (url, httpQueryParameters, load, cache) {
                return this.http(url, 'GET', httpQueryParameters, load, cache);
            },
            post: function (url, httpPostData, load) {
                return this.http(url, 'POST', httpPostData, load);
            },
            put: function (url, httpPutData, load) {
                return this.http(url, 'PUT', httpPutData, load);
            },
            delete: function (url, httpdelData, load) {
                return this.http(url, 'DELETE', httpdelData, load);
            },
            patch: function (url, httppatchData, load) {
                return this.http(url, 'PATCH', httppatchData, load);
            },
            loadingDataTips: function () {
                return layer.load(0, {
                    content: '<div class="loading-box"><div class="loading_01"></div><div class="loading_02"></div></div>'
                });
            },
            /**
             *
             * @param url
             * @param method
             * @param data
             * @param cacheorload
             * get时候 这个参数为是否缓存 默认无缓存
             * 其他方法时候这个参数为是否开启load
             * 默认开启 true为不开启
             * @returns {*}
             */
            http: function (url, method, data, load, cache) {
                var defer = $q.defer();
                var httpParameters = {
                    url: url,
                    method: method,
                    timeout: 15000, // 服务端超时设置
                    headers: {
                        'Content-Type': 'application/json',
                        // 'Authorization': tokenText
                    }
                };
                if (method === 'GET') {
                    httpParameters.params = data;
                    if (cache) {
                        httpParameters.cache = "true";
                    }
                } else {
                    httpParameters.data = data;
                }
                if (!layerIndex && !load) {
                    layerIndex = this.loadingDataTips();
                }
                layercount += 1;
                return $http(httpParameters).success(function (res) {
                    defer.resolve(res);
                })
                    .error(function (res) {
                        defer.reject(res);
                    })
                    .finally(function () {
                        closeLoad();
                    });
            }
        };
    }]);
